package com.zhentao.ai.algorithm;

import com.zhentao.ai.model.DataPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 简化版异常检测算法 - 容易理解的版本
 * 
 * 功能说明：
 * 1. 输入一串数字（比如每天的数据库连接数）
 * 2. 自动找出哪些数字是"异常"的（比如突然特别高或特别低）
 * 3. 输出异常的位置和原因
 * 
 * 原理：就像老师改卷子，大部分学生考70-90分是正常的，
 *      如果有人考20分或者120分，就是异常需要关注
 * 
 * @author zhentao
 * @date 2024-12-19
 */
@Slf4j
@Component
public class SimpleAnomalyDetector {
    
    /**
     * 检测异常的主要方法
     * 
     * @param dataPoints 要检测的数据点列表（比如：每天的访问量、连接数等）
     * @return 异常检测结果
     */
    public SimpleAnomalyResult detectAnomalies(List<DataPoint> dataPoints) {
        log.info("开始异常检测，共有{}个数据点", dataPoints.size());
        
        // 第一步：检查输入数据是否足够
        if (dataPoints == null || dataPoints.size() < 5) {
            log.warn("数据太少，至少需要5个数据点才能进行异常检测");
            return new SimpleAnomalyResult();
        }
        
        // 第二步：把数据点转换成普通的数字数组，方便计算
        List<Double> values = new ArrayList<>();
        for (DataPoint point : dataPoints) {
            values.add(point.getValue().doubleValue());
        }
        
        // 第三步：计算基础统计信息（就像计算班级平均分）
        double average = calculateAverage(values);      // 平均值
        double standardDeviation = calculateStandardDeviation(values, average); // 标准差
        
        log.info("数据统计：平均值={}, 标准差={}", average, standardDeviation);
        
        // 第四步：使用3-sigma规则找异常
        // 3-sigma规则：如果一个数偏离平均值超过3倍标准差，就认为是异常
        // 就像考试，如果平均分70，标准差10，那么40分以下或100分以上就是异常
        List<AnomalyInfo> anomalies = findAnomaliesUsing3Sigma(dataPoints, values, average, standardDeviation);
        
        // 第五步：整理结果
        SimpleAnomalyResult result = new SimpleAnomalyResult();
        result.setAnomalies(anomalies);
        result.setTotalDataPoints(dataPoints.size());
        result.setAnomalyCount(anomalies.size());
        result.setAnomalyRate(calculateAnomalyRate(anomalies.size(), dataPoints.size()));
        result.setAverage(average);
        result.setStandardDeviation(standardDeviation);
        
        log.info("异常检测完成：发现{}个异常点，异常率{:.2f}%", 
                anomalies.size(), result.getAnomalyRate() * 100);
        
        return result;
    }
    
    /**
     * 计算平均值
     * 就像计算班级平均分：把所有分数加起来，除以人数
     */
    private double calculateAverage(List<Double> values) {
        double sum = 0;
        for (double value : values) {
            sum += value;
        }
        return sum / values.size();
    }
    
    /**
     * 计算标准差
     * 标准差表示数据的"散乱程度"：
     * - 标准差小：数据都很接近平均值（比如大家考试分数都在70-80之间）
     * - 标准差大：数据很分散（有人考20分，有人考95分）
     */
    private double calculateStandardDeviation(List<Double> values, double average) {
        double sumOfSquaredDifferences = 0;
        
        // 计算每个数与平均值的差的平方，然后求和
        for (double value : values) {
            double difference = value - average;          // 差值
            sumOfSquaredDifferences += difference * difference;  // 差值的平方
        }
        
        // 除以数据个数，再开平方根
        double variance = sumOfSquaredDifferences / values.size();  // 方差
        return Math.sqrt(variance);  // 标准差
    }
    
    /**
     * 使用3-sigma规则找异常点
     * 
     * 3-sigma规则说明：
     * - 正常情况下，99.7%的数据都在平均值±3倍标准差范围内
     * - 如果超出这个范围，就很可能是异常
     * 
     * 举例：如果数据库连接数平均是100，标准差是20
     *      那么正常范围就是 100-3*20=40 到 100+3*20=160
     *      如果某天连接数是300，就肯定是异常了
     */
    private List<AnomalyInfo> findAnomaliesUsing3Sigma(List<DataPoint> dataPoints, 
                                                       List<Double> values, 
                                                       double average, 
                                                       double standardDeviation) {
        List<AnomalyInfo> anomalies = new ArrayList<>();
        
        // 计算正常范围的上限和下限
        double upperBound = average + 3 * standardDeviation;  // 上限
        double lowerBound = average - 3 * standardDeviation;  // 下限
        
        log.debug("3-sigma正常范围：{:.2f} 到 {:.2f}", lowerBound, upperBound);
        
        // 检查每个数据点
        for (int i = 0; i < values.size(); i++) {
            double value = values.get(i);
            DataPoint dataPoint = dataPoints.get(i);
            
            // 判断是否超出正常范围
            if (value > upperBound) {
                // 数值过高
                AnomalyInfo anomaly = new AnomalyInfo();
                anomaly.setDataPoint(dataPoint);
                anomaly.setAnomalyType("数值过高");
                anomaly.setAnomalyScore(calculateAnomalyScore(value, average, standardDeviation));
                anomaly.setReason(String.format("数值%.2f超出上限%.2f", value, upperBound));
                anomaly.setPosition(i);
                anomalies.add(anomaly);
                
                log.debug("发现异常：位置{}, 数值{}, 原因：{}", i, value, anomaly.getReason());
                
            } else if (value < lowerBound) {
                // 数值过低
                AnomalyInfo anomaly = new AnomalyInfo();
                anomaly.setDataPoint(dataPoint);
                anomaly.setAnomalyType("数值过低");
                anomaly.setAnomalyScore(calculateAnomalyScore(value, average, standardDeviation));
                anomaly.setReason(String.format("数值%.2f低于下限%.2f", value, lowerBound));
                anomaly.setPosition(i);
                anomalies.add(anomaly);
                
                log.debug("发现异常：位置{}, 数值{}, 原因：{}", i, value, anomaly.getReason());
            }
            // 如果在正常范围内，就不做任何处理
        }
        
        return anomalies;
    }
    
    /**
     * 计算异常分数
     * 异常分数表示"这个异常有多严重"：
     * - 分数越高，异常越严重
     * - 比如偏离平均值1倍标准差，分数是1
     * - 偏离平均值5倍标准差，分数是5（非常严重）
     */
    private double calculateAnomalyScore(double value, double average, double standardDeviation) {
        if (standardDeviation == 0) {
            return 0;  // 如果标准差为0，说明所有数据都一样，没有异常
        }
        
        // 计算偏离了多少倍标准差
        return Math.abs(value - average) / standardDeviation;
    }
    
    /**
     * 计算异常率
     * 异常率 = 异常数据的个数 / 总数据个数
     * 比如100个数据中有5个异常，异常率就是5%
     */
    private double calculateAnomalyRate(int anomalyCount, int totalCount) {
        if (totalCount == 0) {
            return 0;
        }
        return (double) anomalyCount / totalCount;
    }
    
    // =============== 内部数据类 ===============
    
    /**
     * 异常检测结果
     */
    public static class SimpleAnomalyResult {
        private List<AnomalyInfo> anomalies = new ArrayList<>();  // 发现的异常列表
        private int totalDataPoints;                              // 总数据点数
        private int anomalyCount;                                 // 异常点数量
        private double anomalyRate;                               // 异常率
        private double average;                                   // 数据平均值
        private double standardDeviation;                         // 数据标准差
        
        // getter和setter方法
        public List<AnomalyInfo> getAnomalies() { return anomalies; }
        public void setAnomalies(List<AnomalyInfo> anomalies) { this.anomalies = anomalies; }
        public int getTotalDataPoints() { return totalDataPoints; }
        public void setTotalDataPoints(int totalDataPoints) { this.totalDataPoints = totalDataPoints; }
        public int getAnomalyCount() { return anomalyCount; }
        public void setAnomalyCount(int anomalyCount) { this.anomalyCount = anomalyCount; }
        public double getAnomalyRate() { return anomalyRate; }
        public void setAnomalyRate(double anomalyRate) { this.anomalyRate = anomalyRate; }
        public double getAverage() { return average; }
        public void setAverage(double average) { this.average = average; }
        public double getStandardDeviation() { return standardDeviation; }
        public void setStandardDeviation(double standardDeviation) { this.standardDeviation = standardDeviation; }
        
        /**
         * 生成人类可读的报告
         */
        public String generateReport() {
            StringBuilder report = new StringBuilder();
            report.append("=== 异常检测报告 ===\n");
            report.append(String.format("总数据点数：%d\n", totalDataPoints));
            report.append(String.format("异常点数量：%d\n", anomalyCount));
            report.append(String.format("异常率：%.2f%%\n", anomalyRate * 100));
            report.append(String.format("数据平均值：%.2f\n", average));
            report.append(String.format("数据标准差：%.2f\n", standardDeviation));
            report.append("\n=== 异常详情 ===\n");
            
            if (anomalies.isEmpty()) {
                report.append("未发现异常数据\n");
            } else {
                for (int i = 0; i < anomalies.size(); i++) {
                    AnomalyInfo anomaly = anomalies.get(i);
                    report.append(String.format("%d. %s (异常分数:%.2f) - %s\n", 
                        i + 1, anomaly.getAnomalyType(), anomaly.getAnomalyScore(), anomaly.getReason()));
                }
            }
            
            return report.toString();
        }
    }
    
    /**
     * 单个异常信息
     */
    public static class AnomalyInfo {
        private DataPoint dataPoint;      // 异常的数据点
        private String anomalyType;       // 异常类型（数值过高/过低）
        private double anomalyScore;      // 异常分数（越高越严重）
        private String reason;            // 异常原因说明
        private int position;             // 在数据中的位置
        
        // getter和setter方法
        public DataPoint getDataPoint() { return dataPoint; }
        public void setDataPoint(DataPoint dataPoint) { this.dataPoint = dataPoint; }
        public String getAnomalyType() { return anomalyType; }
        public void setAnomalyType(String anomalyType) { this.anomalyType = anomalyType; }
        public double getAnomalyScore() { return anomalyScore; }
        public void setAnomalyScore(double anomalyScore) { this.anomalyScore = anomalyScore; }
        public String getReason() { return reason; }
        public void setReason(String reason) { this.reason = reason; }
        public int getPosition() { return position; }
        public void setPosition(int position) { this.position = position; }
    }
}
